﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Practices.Unity;
using SpectrumAnalyser.Common.Hosting;
using SpectrumAnalyser.Config.Client;
using SpectrumAnalyser.Config.Contract;
using SpectrumAnalyser.ModelObjects.Enum;
using SpectrumAnalyser.ServiceClientProxy;
using SpectrumAnalyser.Services.ExpertiseResultStorageServiceContracts;

namespace SpectrumAnalyser.Config.ServiceClientExample
{
    class Program
    {
        private static void Main(string[] args)
        {
            var fooParameter = Expression.Parameter(typeof(Foo));
            var valueParameter = Expression.Parameter(typeof(string));
            var propertyInfo = typeof(Foo).GetProperty("Name");
            var assignment = Expression.Assign(Expression.MakeMemberAccess(fooParameter, propertyInfo), valueParameter);
            var assign = Expression.Lambda<Action<Foo, string>>(assignment, fooParameter, valueParameter);
            Action<Foo, string> fnSet = assign.Compile();

            var foo = new Foo();
            fnSet(foo, "ddd");

            var e = new Foo {Name = "Tom", Id = 1};
            var e2 = new Foo();
            Update(e, e2, x => x.Name, x => x.Id);
            

            var container = new UnityContainer();

            Console.WriteLine("Enter config service address:");

            var hostUri = WcfHelper.GetEndpointUri(UriScheme.Http, "IConfigService");

            container.Resolve<ConfigClient>().Initialize(hostUri.ToString());

            var configService = container.Resolve<IConfigService>();
            configService.Ping();

            //mapped to MyInstance
            container.Resolve<ClientBootstrapperBase>(new ParameterOverride("instanceName", "WorkInstance"))
                      .RegisterServices(new List<Type>
                          {
                              typeof (IExpertiseStorageServiceContract)
                          });

            var expertiseStorageServiceContract = container.Resolve<IExpertiseStorageServiceContract>();
            expertiseStorageServiceContract.Ping();
            

            var i = configService.GetInstances();
        }

        public static void Update<TEntity>(TEntity entity, TEntity updateEntity, params Expression<Func<TEntity, object>>[] expression)
        {
            foreach (Expression<Func<TEntity, object>> expression1 in expression)
            {
                MemberExpression memberExpression = null;
                if (expression1.Body is UnaryExpression)
                {
                    var unaryExpression = (UnaryExpression) expression1.Body;
                    memberExpression = (MemberExpression) unaryExpression.Operand;
                }
                if (expression1.Body is MemberExpression)
                {
                    memberExpression = expression1.Body as MemberExpression;
                }
                if (memberExpression == null)
                {
                    continue;
                }

                var value = expression1.Compile()(entity);
                var prop = (PropertyInfo)memberExpression.Member;
                if (prop.CanWrite)
                {
                    prop.SetValue(updateEntity, value, null);
                }
            }
        }

        public static Expression<Action<TEntity, TValue>> Set<TEntity, TValue>(Expression<Func<TEntity, TValue>> propertyGetExpression)
        {
            var entityParameterExpression = (ParameterExpression)(((MemberExpression)(propertyGetExpression.Body)).Expression);
            var valueParameterExpression = Expression.Parameter(typeof(TValue));

            return Expression.Lambda<Action<TEntity, TValue>>(
                Expression.Assign(propertyGetExpression.Body, valueParameterExpression),
                entityParameterExpression,
                valueParameterExpression);
        }

        /*public static T Get<T>() where T : Foo
        {
            return new Foo();
        }*/
    }

    public class Foo
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}
